package com.winchain.chainbill.asset.biz.credit.service.impl;

import com.shell.bee.acct.AcctBlcService;
import com.shell.bee.acct.account.po.AcctBkp;
import com.shell.bee.acct.transaction.po.AcctTxRec;
import com.shell.bee.acct.transaction.vo.AcctInfo;
import com.shell.bee.base.exception.UnCheckMsgException;
import com.shell.bee.contract.ContService;
import com.shell.bee.contract.po.ContBas;
import com.shell.constant.rel.AssetCode;
import com.shell.framework.utils.CommonDataUtil;
import com.shell.framework.utils.MessageSender;
import com.shell.governor.modules.message.keyword.CreditOptKeyWord;
import com.winchain.chainbill.ChainBillUtil;
import com.winchain.chainbill.asset.biz.credit.AssetEvent;
import com.winchain.chainbill.asset.biz.credit.rx.CreditAssetMsgSubscriber;
import com.winchain.chainbill.asset.biz.credit.rx.CreditAssetTranBatchSubscriber;
import com.winchain.chainbill.asset.biz.credit.rx.CreditAssetTranForInitSubscriber;
import com.winchain.chainbill.asset.biz.credit.rx.CreditAssetTranSubscriber;
import com.winchain.chainbill.asset.biz.credit.service.CreditAssetMgtService;
import com.winchain.chainbill.trade.service.BillAcctService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import rx.Observable;

@Service("creditAssetMgtService")
public class CreditAssetMgtServiceImpl implements CreditAssetMgtService {
	@Autowired
	private BillAcctService billAcctService;
	@Autowired
	private CreditAssetTranSubscriber creditAssetTranSubscriber;
	@Autowired
	private CreditAssetTranBatchSubscriber creditAssetTranBatchSubscriber;
	@Autowired
	private CreditAssetMsgSubscriber creditAssetMsgSubscriber;
	@Autowired
	private CreditAssetTranForInitSubscriber creditAssetTranForInitSubscriber;
	@Autowired
	private ContService contService;
	@Autowired
	private AcctBlcService acctBlcService;

	public String distribute(String strategy, BigDecimal amount, String grpId, String finId, String... cusIds) {
		BigDecimal amt = new BigDecimal(0);
		BigDecimal length = new BigDecimal(cusIds.length);
		if (strategy.equals("1")) {
			amt = amount;
		} else {
			amt = amount.divide(length, 2, RoundingMode.DOWN);
		}
		AcctInfo sourceAcct = new AcctInfo();
		sourceAcct.setCustId(finId);
		sourceAcct.setAcctType("1");
		sourceAcct.setCurrCode(AssetCode.XQT.name());
		sourceAcct = this.billAcctService.getAcctInfo(sourceAcct);
		if (sourceAcct == null) {
			throw new UnCheckMsgException("������������������");
		}
		BigDecimal totalAmt = amt.multiply(length);
		if (checkAmt(totalAmt, sourceAcct)) {
			throw new UnCheckMsgException(
					"������������������������������������������������������������������������������������");
		}
		List<AcctTxRec> records = new ArrayList();
		for (String cusId : cusIds) {
			AcctTxRec crTx = new AcctTxRec();
			crTx.setTxAmt(amt);
			crTx.setOptType("qt_inc");
			crTx.setTxType("qt_credit");
			crTx.setBizId(cusId);

			records.add(crTx);
		}
		Object event = new AssetEvent();
		((AssetEvent) event).setRecords(records);

		((AssetEvent) event).setAcctInfo(sourceAcct);
		((AssetEvent) event).setValue("finId", finId);
		((AssetEvent) event).setValue("grpId", grpId);

		Object observers = Observable.just(event);

		((Observable) observers).subscribe(this.creditAssetTranBatchSubscriber);
		if (ChainBillUtil.onChain()) {
			Object txSnHost = ((AssetEvent) event).getValue("txSnHost");
			if (txSnHost != null) {
				return (String) txSnHost;
			}
		}
		return null;
	}

	public String distribute(BigDecimal amount, String grpId, String finId, String cusId) {
		BigDecimal totalAmt = amount;
		ContBas contBas = this.contService.getContBas(finId, cusId, "40", "6");
		AcctInfo acctInfo = new AcctInfo();
		acctInfo.setCustId(cusId);
		acctInfo.setBkpPrdCode(grpId);
		acctInfo.setBkpCttNo(contBas.getContSn());
		acctInfo.setAcctType("1");
		acctInfo.setCurrCode(AssetCode.XQT.name());
		acctInfo = this.billAcctService.getAcctInfo(acctInfo);
		if (acctInfo == null) {
			throw new UnCheckMsgException("������������������");
		}
		int cmpResult = acctInfo.getAcctAmt().compareTo(amount);
		if (cmpResult == 0) {
			return null;
		}
		BigDecimal usedAmt = acctInfo.getUsedAmt();
		BigDecimal blkAmt = acctInfo.getAcctBlk();
		String optType = "qt_inc";

		List<AcctTxRec> finRecords = new ArrayList();
		if (acctInfo != null) {
			if (amount.compareTo(usedAmt.add(blkAmt)) < 0) {
				throw new UnCheckMsgException("������������������������(��������+��������)");
			}
			if (cmpResult > 0) {
				amount = acctInfo.getAcctAmt().subtract(amount);
				optType = "qt_red";
			} else {
				amount = amount.subtract(acctInfo.getAcctAmt());
			}
		}
		AcctInfo sourceAcct = new AcctInfo();
		sourceAcct.setCustId(finId);
		sourceAcct.setAcctType("1");
		sourceAcct.setCurrCode(AssetCode.XQT.name());
		sourceAcct = this.billAcctService.getAcctInfo(sourceAcct);
		if (("qt_inc".equals(optType)) && (checkAmt(amount, sourceAcct))) {
			throw new UnCheckMsgException(
					"������������������������������������������������������������������������������������");
		}
		AcctTxRec txRec = new AcctTxRec();
		txRec.setTxAmt(amount);
		txRec.setTxType("qt_credit");
		txRec.setOptType(optType);
		txRec.setBizId(cusId);

		List<AcctTxRec> list = new ArrayList();
		list.add(txRec);

		AssetEvent<AcctTxRec> event = new AssetEvent();
		event.setRecords(list);
		event.setFinRecords(finRecords);
		event.setAcctInfo(sourceAcct);
		event.setTotalAmt(totalAmt);
		event.setValue("grpId", grpId);

		Observable<AssetEvent<AcctTxRec>> observers = Observable.just(event);

		observers.subscribe(this.creditAssetTranSubscriber);
		observers.subscribe(this.creditAssetMsgSubscriber);
		if (ChainBillUtil.onChain()) {
			Object txSnHost = event.getValue("txSnHost");
			if (txSnHost != null) {
				return (String) txSnHost;
			}
		}
		return null;
	}

	public String distribute(BigDecimal amount, String grpId, String finId, String cusId, String currCode) {
		BigDecimal totalAmt = amount;
		String bizType = "40";
		if (AssetCode.XTB.name().equals(currCode)) {
			bizType = "41";
		} else if (AssetCode.FQT.name().equals(currCode)) {
			bizType = "42";
		}
		ContBas contBas = this.contService.getContBas(finId, cusId, bizType, "6");
		List<AcctTxRec> records = new ArrayList();
		AcctTxRec crTx = new AcctTxRec();
		AcctInfo sourceAcct = new AcctInfo();

		List<AcctTxRec> finRecords = new ArrayList();
		if (contBas == null) {
			crTx.setTxAmt(amount);
			crTx.setOptType("qt_inc");
			crTx.setTxType("qt_credit");
			crTx.setBizId(cusId);
			crTx.setCurrCode(currCode);
			records.add(crTx);
		} else {
			AcctInfo acctInfo = new AcctInfo();
			acctInfo.setCustId(cusId);
			acctInfo.setBkpPrdCode(grpId);
			acctInfo.setBkpCttNo(contBas.getContSn());
			acctInfo.setAcctType("1");
			acctInfo.setCurrCode(currCode);
			acctInfo = this.billAcctService.getAcctInfo(acctInfo);
			if (acctInfo == null) {
				throw new UnCheckMsgException("������������������");
			}
			int cmpResult = acctInfo.getAcctAmt().compareTo(amount);
			if (cmpResult == 0) {
				return null;
			}
			BigDecimal usedAmt = acctInfo.getUsedAmt();
			BigDecimal blkAmt = acctInfo.getAcctBlk();
			String optType = "qt_inc";
			if (acctInfo != null) {
				if (amount.compareTo(usedAmt.add(blkAmt)) < 0) {
					throw new UnCheckMsgException("������������������������(��������+��������)");
				}
				if (cmpResult > 0) {
					amount = acctInfo.getAcctAmt().subtract(amount);
					optType = "qt_red";
				} else {
					amount = amount.subtract(acctInfo.getAcctAmt());
				}
			}
			sourceAcct.setCustId(finId);
			sourceAcct.setAcctType("1");
			sourceAcct.setCurrCode(currCode);
			sourceAcct = this.billAcctService.getAcctInfo(sourceAcct);

			crTx.setTxAmt(amount);
			crTx.setTxType("qt_credit");
			crTx.setOptType(optType);
			crTx.setBizId(cusId);
			crTx.setCurrCode(currCode);

			records.add(crTx);
		}
		AssetEvent<AcctTxRec> event = new AssetEvent();
		event.setRecords(records);
		event.setFinRecords(finRecords);
		event.setAcctInfo(sourceAcct);
		event.setTotalAmt(totalAmt);
		event.setValue("grpId", grpId);
		event.setValue("finId", finId);
		event.setValue("currCode", currCode);

		Observable<AssetEvent<AcctTxRec>> observers = Observable.just(event);
		if (contBas == null) {
			observers.subscribe(this.creditAssetTranForInitSubscriber);
		} else {
			observers.subscribe(this.creditAssetTranSubscriber);
		}
		observers.subscribe(this.creditAssetMsgSubscriber);
		if (ChainBillUtil.onChain()) {
			Object txSnHost = event.getValue("txSnHost");
			if (txSnHost != null) {
				return (String) txSnHost;
			}
		}
		return null;
	}

	private boolean checkAmt(BigDecimal totalAmt, AcctInfo sourceAcct) {
		BigDecimal acctAmt = sourceAcct.getAcctBlc().subtract(sourceAcct.getAcctBlk());
		return acctAmt.compareTo(totalAmt) < 0;
	}

	public String updateBkpState(String bkpId, String state, String cusId, String remark) {
		AcctBkp bkp = this.acctBlcService.selectAcctBkpById(bkpId);
		String str = "";
		if ("1".equals(state)) {
			bkp.setQuotaState("0");
			str = "������������";
			if (AssetCode.XTB.name().equals(bkp.getCurrCode())) {
				sendSmsMessage("MT02628", cusId, remark);
			} else if (AssetCode.FQT.name().equals(bkp.getCurrCode())) {
				sendSmsMessage("MT02630", cusId, remark);
			}
		} else if ("0".equals(state)) {
			bkp.setQuotaState("1");
			str = "������������";
			if (AssetCode.XTB.name().equals(bkp.getCurrCode())) {
				sendSmsMessage("MT02629", cusId, remark);
			} else if (AssetCode.FQT.name().equals(bkp.getCurrCode())) {
				sendSmsMessage("MT02631", cusId, remark);
			}
		}
		this.acctBlcService.update(bkp);
		return str;
	}

	private void sendSmsMessage(String messageTplId, String entId, String remark) {
		try {
			CreditOptKeyWord keyword = new CreditOptKeyWord();
			keyword.setRemark(remark);
			MessageSender.sendMessageByTmpl(CommonDataUtil.getCurEntId(), messageTplId, keyword, entId);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
